package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"

	"gitee.com/czy233/go-ceph/rados"
)

type Ceph struct {
	ioctx *rados.IOContext
	conn  *rados.Conn
	cli   *http.Client
}

//以TLS的形式从其他机构获得恢复数据
func (c *Ceph) GetBlockFromTLS(obj string, from int) ([]byte, error) {
	// IP := "10.10.9.20"
	IP := ClusterName(from)
	data := make([]byte, 4096*1024)
	data, err := c.ReadBlockFromClustersTLS(IP, obj)
	if err != nil {
		fmt.Println("cluster", Cluster, ":", "获取失败", obj, ": http error")
		return data, err
	} else {
		fmt.Println("cluster", Cluster, ":", "获取成功", obj)
		return data, nil
	}
}

//以TLS的形式从其他机构获得恢复数据
func (c *Ceph) ReadBlockFromClustersTLS(IP string, obj string) ([]byte, error) {
	url := IP + obj
	fmt.Println("cluster", Cluster, ":", url)
	resp, err := c.cli.Get(url)
	if err != nil {
		fmt.Println("Get error:", err)
		return nil, err
	}
	defer resp.Body.Close()
	ret, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if len(ret) == 0 {
		fmt.Println("cluster", Cluster, ":", "接收数据为空", obj)
		return ret, errors.New("nil")
	}
	fmt.Println("cluster", Cluster, ":", "接收数据", obj, len(ret))
	return ret, nil
}

//从其他机构获取数据
func ReadFromOtherClusters(IP string, port int, obj string, offset int, length int) []byte {
	url := "http://" + IP + ":" + strconv.Itoa(port) + "/get?oid=" + obj + "&off=" + strconv.Itoa(offset) + "&len=" + strconv.Itoa(length)
	fmt.Println(url)
	resp, err := http.Get(url)
	if err != nil {
		return nil
	}
	defer resp.Body.Close()
	ret, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil
	}
	return ret
}

//向其他机构写数据
func WriteToOtherClusters(IP string, port int, obj_id string, content []byte) error {
	url := "http://" + IP + ":" + strconv.Itoa(port) + "/put"
	obj := Object{
		Obj_id:  obj_id,
		Content: content,
	}
	obj_json, err := json.Marshal(obj)
	if err != nil {
		return err
	}

	resp, err := http.Post(url, "application/json", bytes.NewBuffer(obj_json))
	if err != nil {
		return err
	}
	resp_body, _ := ioutil.ReadAll(resp.Body)
	fmt.Printf("write obj: %s to %s, length: %d, resp: %s\n", obj_id, url, len(obj.Content), string(resp_body))
	return nil
}

//使用HTTP获取数据
func (c *Ceph) GetBlockDataFromHttp(obj Transaction) (data []byte) {
	IP := ClusterIp(int(obj.From))
	data = make([]byte, 4096*1024)
	data = ReadFromOtherClusters(IP, ClusterPort, string(obj.Hash), 0, 4096*1024)
	if data == nil {
		fmt.Println("error when read obj", string(obj.Hash), ": http error")
	} else {
		fmt.Println("success get obj", string(obj.Hash))
	}
	return
}

//获取本地数据
func (c *Ceph) getBlockData(oid string) (data []byte) {
	data = make([]byte, 4096*1024)
	ret, err := c.ioctx.Read(oid, data, 0)
	if err != nil {
		fmt.Println("error when read obj:", err)
		return
	}
	if ret != 4096*1024 {
		fmt.Println("error when read obj")
	}
	return
}

//写本地数据
func (c *Ceph) writedata(oid string, data []byte) {
	err := c.ioctx.WriteFullWithPutHash(oid, data)
	if err != nil {
		fmt.Println("error when write obj:", err)
	}
}

// 删除本地数据
func (c *Ceph) deletedata(oid string) {
	err := c.ioctx.Delete(oid)
	if err != nil {
		fmt.Println("error when delete obj:", err)
	}
}

// 生成ceph接口
func (c *Ceph) CephInit() {
	conn, err := rados.NewConn()
	if err != nil {
		fmt.Println("error when invoke a new connection:", err)
	}

	err = conn.ReadDefaultConfigFile()
	if err != nil {
		fmt.Println("error when read default config file:", err)
	}

	err = conn.Connect()
	if err != nil {
		fmt.Println("error when connect:", err)
	}

	fmt.Println("connect ceph cluster ok!")

	ioctx, err := conn.OpenIOContext("testbench")
	if err != nil {
		fmt.Println("error when open IO context:", err)
	}
	c.ioctx = ioctx
	c.conn = conn
	c.cli = tls_client()
}

func (c *Ceph) Free() {
	c.conn.Shutdown()
}
